package Utils

import (
	"sync"
)

/*
	线程安全map，会牺牲一部分性能，适用于并发场景不高但对数据安全有威胁的地方
	Usage:
		m.Set("123", 111)
		m.Set("1232", 1112)
		fmt.Println(m.Get("123"))
		m.Remove("123")
		fmt.Println(m.Get("123"))

		fmt.Println(m.Values())
		fmt.Println(m.Keys())
		fmt.Println(m.Items())
		m.Pop()
*/

type SafeMap struct {
	m      map[string]interface{}
	keys   []string
	values []interface{}
	l      *sync.RWMutex
}

func (s *SafeMap) Set(key string, value interface{}) {
	s.l.Lock()
	defer s.l.Unlock()
	s.m[key] = value
	s.keys = append(s.keys, key)
	s.values = append(s.values, value)
}

func (s *SafeMap) Remove(key string) {
	s.l.Lock()
	defer s.l.Unlock()
	var idx int
	var exist bool
	for index, k := range s.keys {
		if k == key {
			idx = index
			exist = true
		}
	}
	if !exist {
		return
	}

	keys := []string{}
	values := []interface{}{}
	keys = append(keys, s.keys[:idx]...)
	keys = append(keys, s.keys[idx+1:]...)

	values = append(values, s.values[:idx]...)
	values = append(values, s.values[idx+1:]...)

	s.keys = keys
	s.values = values
	delete(s.m, key)

}

func (s *SafeMap) Pop() (string, interface{}) {
	// 从尾部pop一个键值对
	s.l.Lock()
	defer s.l.Unlock()
	if len(s.keys) >= 1 {
		deleteKey := s.keys[len(s.keys)-1]
		deleteValue := s.values[len(s.keys)-1]

		keys := []string{}
		values := []interface{}{}
		keys = append(keys, s.keys[:(len(s.keys)-1)]...)
		values = append(values, s.values[:(len(s.keys)-1)]...)

		s.keys = keys
		s.values = values
		delete(s.m, deleteKey)

		return deleteKey, deleteValue
	}
	return "", nil
}

func (s *SafeMap) Get(key string) interface{} {
	s.l.RLock()
	defer s.l.RUnlock()
	if val, ok := s.m[key]; ok {
		return val
	}
	return nil
}

func (s *SafeMap) Keys() []string {
	s.l.RLock()
	defer s.l.RUnlock()
	return s.keys
}

func (s *SafeMap) Values() []interface{} {
	s.l.RLock()
	defer s.l.RUnlock()

	return s.values
}

func (s *SafeMap) Items() map[string]interface{} {
	s.l.RLock()
	defer s.l.RUnlock()

	return Copy(s.m)
}

func NewSafeMap() *SafeMap {
	return &SafeMap{l: new(sync.RWMutex), m: make(map[string]interface{}), keys: []string{}, values: []interface{}{}}
}

func Copy(m map[string]interface{}) map[string]interface{} {
	c := make(map[string]interface{})
	for k, v := range m {
		c[k] = v
	}
	return c
}
